package com.waves.spring.boot.run;

import lombok.SneakyThrows;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.lang.reflect.Constructor;
import java.util.List;

/**
 * 1.SpringApplicationRunListeners 实现事件发布
 */
public class RunApplication1 {
    @SneakyThrows
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication();
        app.addListeners(i -> System.out.println("事件："+i.getClass()));

        // 获取事件发送器的实现类类名
        List<String> names = SpringFactoriesLoader.loadFactoryNames(
                SpringApplicationRunListener.class, RunApplication1.class.getClassLoader());
        for (String name : names) {
            System.out.println("事件发布器名称：" + name);
            Class<?> clazz = Class.forName(name);
            Constructor<?> constructor = clazz.getConstructor(SpringApplication.class, String[].class);
            SpringApplicationRunListener publisher = (SpringApplicationRunListener) constructor.newInstance(app, args);

            // 开始发布事件
            // spring boot 开始启动（启动事件）
            DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
            publisher.starting(bootstrapContext);
            // 环境信息准备完毕（环境事件）
            publisher.environmentPrepared(bootstrapContext, new StandardEnvironment());
            // 创建 spring 容器，调用初始化器之后发布此事件（容器准备事件）
            GenericApplicationContext context = new GenericApplicationContext();
            publisher.contextPrepared(context);
            // 所有 bean definition 加载完毕（容器加载完毕事件）
            publisher.contextLoaded(context);
            // spring 容器初始化完毕（调用 refresh() 方法后）
            context.refresh();
            // started事件表示应用程序已经启动，但还没有准备好
            publisher.started(context, null);
            // spring boot 启动完毕(ready事件，表示应用程序已经 完全启动 并准备好接收请求)
            publisher.ready(context, null);
            // 启动过程中出现异常，spring boot 启动出错（异常事件）
            publisher.failed(context, new Exception("出错了"));
        }
    }
}
